/*! \file VWidget.h
    包含类 \a VWidget 的头文件.

    类: \b VWidget
*/

#ifndef VWIDGET_H
#define VWIDGET_H

#include "VBase.h"

//! 可视化组件
/*!
    所有可视化组件必须继承自此类.
*/
class VWidget :
    public VBase
{
public:
    //! 缺省构造函数
    VWidget();
    //! 直接指定区域矩形的构造函数
    /*!
        \param x
            组件的横向坐标.
        \param y
            组件的纵向坐标.
        \param w
            组件的宽度.
        \param h
            组件的高度.

        \sa _x, _y, _h, _w, setGeometry 和 geometry
    */
    VWidget(int x, int y, int w, int h);
    //! 析构函数
    virtual ~VWidget();

    //! 暂时没有实现拷贝构造和赋值运算符, 为避免指针冲突
protected:
    //! 拷贝构造(空)
    VWidget(const VWidget&);
    //! 赋值运算符(空)
    VWidget& operator=(const VWidget&);

    //! 通用接口
public: // common interfaces
    //! 初始化组件
    /*!
        作初始化, 一般来说在构造并设置完矩形之后被调用, 可以包含一些与组件矩形相关的初始化操作.
    */
    virtual void init();

    //! 渲染组件
    /*!
        绘制此可视化组件.

        \warning
            不要在此函数内尝试修改任何成员变量, 不要作动画.

        \return
            如果此组件进行了绘制或者要子组件需要绘制, 返回true, 否则, 返回false.

        \sa animate
    */
    virtual bool render() const;

    //! 动画组件
    /*!
        动画此可视化组件, 在其中自行判断时钟问题, 调用 \a VMain::getClock 函数进行控制时钟.

        \sa render 和 getClock.

    */
    virtual void animate();

    //! 组件属性设置
public: // properties
    //! 设置包含组件的容器
    /*!
        设置此组件的容器, 将会在容器中调用 \a VContainer::insert 加入此组件.
        如果此类已有容器, 则在原来的容器中调用 \a VContainer::remove 移除此组件, 并添加到新的容器中.
        如果要放弃容器(独立出来), 可以通过传入NULL来实现.

        \param parent
            指定此组件所在的容器
        \sa _parent 和 parent
    */
    virtual void setParent(VContainer* parent);
    //! 此组件所在的容器
    /*!
        \return
            此组件当前的容器指针, 如果没有容器, 则返回NULL.

        \sa _parent 和 setParent
    */
    virtual VContainer* parent();

    //! 设置组件显示或者隐藏.
    /*!
        设置此组件是否可视.

        \param visible
            true为显示, false为隐藏.
        \sa _visible 和 isVisible
    */
    virtual void setVisible(bool visible);
    //! 获取组件当前显示状态.
    /*!
        获取此组件当前是否可视.

        \return visible
            true为显示, false为隐藏.
        \sa _visible 和 setVisible
    */
    virtual bool isVisible() const;

    //! 设置组件的区域矩形
    /*!
        设置此组件的位置, 大小属性.
        由x, y, w, h确定一个矩形区域.
        这个函数的是通过调用 \a VWidget::move 和 \a VWidget::resize 来实现的.

        \param x
            组件的横向坐标.
        \param y
            组件的纵向坐标.
        \param w
            组件的宽度.
        \param h
            组件的高度.
        \sa _x, _y, _h, _w, geometry, move 和 resize
    */
    virtual void setGeometry(int x, int y, int w, int h);
    //! 获得组件的区域矩形
    /*!
        通过参数返回此区域矩形.

        \param [out] x
            返回组件的横向坐标.
        \param [out] y
            返回组件的纵向坐标.
        \param [out] w
            返回组件的宽度.
        \param [out] h
            返回组件的高度.
        \sa _x, _y, _h, _w 和 setGeometry
    */
    virtual void geometry(int* x, int* y, int* w, int* h)  const;

    //! 设置是否需要追踪组件上的鼠标移动事件
    /*!
        即是否会被响应 \a VWidget::mouseMoveEvent 事件.
        这是出于效率考虑的, 如果每个组件都要进行处理鼠标移动事件, \n
        则会导致响应别的事件, 绘制循环轻微阻塞, 导致浪费.

        \warning
            相对 \a NO_MOUSE_TRACE 宏, 优先级比较低.

        \param open
            true为追踪, false为不追踪.
        \sa _mousetrace, mouseTrace, mouseMoveEvent, mouseMove, NO_MOUSE_TRACE
    */
    virtual void setMouseTrace(bool open);
    //! 获得组件是否处理鼠标移动追踪事件
    /*!
        \return
            true为追踪, false为不追踪.
        \sa _mousetrace, setMouseTrace, mouseMoveEvent, mouseMove, NO_MOUSE_TRACE
    */
    virtual bool mouseTrace() const;

    //! 移动组件
    /*!
        设置组件的位置(横纵坐标).
        \param x
            指定新的横坐标
        \param y
            指定新的纵坐标
        \sa _x, _y, pos
    */
    virtual void move(int x, int y);
    //! 获得组件位置
    /*!
        获取到组件的位置(纵横坐标).
        \param [out] x
            用于返回当前的横坐标
        \param [out] y
            用于返回当前的纵坐标
        \sa _x, _y, move
    */
    virtual void pos(int* x, int* y) const;

    //! 设置组件的大小
    /*!
        通过改变宽高长度来实现改变组件大小.
        \param w
            用于设置当前组件的宽度
        \param h
            用于设置当前组件的高度
        \sa _w, _h, size
    */
    virtual void resize(int w, int h);
    //! 获得组件的大小
    /*!
        通过参数返回组件的大小.
        \param [out] w
            用于返回当前组件的宽度
        \param [out] h
            用于返回当前组件的高度
        \sa _w, _h, resize
    */
    virtual void size(int* w, int* h) const;

    //! 返回当前横坐标的引用
    /*!
        因为返回的是引用, 所以可以进行读取或者修改.\n
        如
        \code
        VWidget widget;

        widget.xpos() += 2;             // 将widget的横坐标向右偏移2个像素
        printf("%d\n", widget.xpos());  // 输出widget当前的横坐标
        \endcode
        \return
            返回的横坐标
    */
    virtual int& xpos();
    virtual int& ypos();
    virtual int& width();
    virtual int& height();

    virtual bool inArea(int x, int y)  const;

    virtual void setZOrder(int zorder);
    virtual int zOrder() const;


    void* privateData();
    void setPrivateData(void* pdata);

protected:
    int _x, _y, _w, _h;
    bool _mousetrace;
    bool _visible;
    bool _mousedown;
    int _zorder;
    void* _privatedata;
    VContainer* _parent;

public: // event
    virtual bool mouseDownEvent(int x, int y);
    virtual bool mouseUpEvent(int x, int y);
    virtual bool mouseMoveEvent(int x, int y, bool mousestat);

public: // event handler
    virtual void mouseDown(int x, int y);
    virtual void mouseUp(int x, int y);
    virtual void mouseClick(int x, int y);
    virtual void mouseMove(int x, int y, bool mousestat);

protected:    // class type
    static const CLASS_TYPE _clstype = T_WIDGET;
public:
    virtual CLASS_TYPE classType()  const;
};

#endif
